﻿using System;
using System.Collections.Generic;
using System.Text;

namespace Savage.DotNetLibrary.ProtocolLibrary.GPS
{
    public class GPSData
    {
        private byte[] _versionId;
        /// <summary>
        /// Indicates the version of GPSInfoIFD. The version is given as 2.2.0.0. This tag is mandatory when GPSInfo tag is present.
        /// </summary>
        public byte[] VersionId
        {
            get { return _versionId; }
            set { _versionId = value; }
        }
        
        private GPSPosition _latitude;
        /// <summary>
        /// Indicates the latitude.
        /// </summary>
        public GPSPosition Latitude
        {
            get { return _latitude; }
            set { _latitude = value; }
        }

        private GPSPosition _longitude;
        /// <summary>
        /// Indicates the longitude.
        /// </summary>
        public GPSPosition Longitude
        {
            get { return _longitude; }
            set { _longitude = value; }
        }

        private GPSAltitudeRef _altitudeRef;
        /// <summary>
        /// Indicates the altitude used as the reference altitude. If the altitude is below sea level, the altitude is indicated as an absolute value in the GPSAltitude tag.
        /// </summary>
        public GPSAltitudeRef AltitudeRef
        {
            get { return _altitudeRef; }
            set { _altitudeRef = value; }
        }

        private decimal _altitude;
        /// <summary>
        /// Indicates the altitude based on the reference in GPSAltitudeRef. The reference unit is meters.
        /// </summary>
        public decimal Altitude
        {
            get { return _altitude; }
            set { _altitude = value; }
        }

        private DateTime? _utcDateTimeStamp;
        /// <summary>
        /// Indicates the date and time as UTC (Coordinated Universal Time).
        /// </summary>
        public DateTime? UtcDateTimeStamp
        {
            get { return _utcDateTimeStamp; }
            set { _utcDateTimeStamp = value; }
        }

        private string _satellites;
        /// <summary>
        /// Indicates the GPS satellites used for measurements. This tag can be used to describe the number of satellites, their ID number, angle of elevation, azimuth, SNR and other information.
        /// </summary>
        public string Satellites
        {
            get { return _satellites; }
            set { _satellites = value; }
        }

        private GPSStatus _status;
        /// <summary>
        /// Indicates the status of the GPS receiver when the image is recorded.
        /// </summary>
        public GPSStatus Status
        {
            get { return _status; }
            set { _status = value; }
        }

        private GPSMeasureMode _measureMode;
        /// <summary>
        /// Indicates the GPS measurement mode.
        /// </summary>
        public GPSMeasureMode MeasureMode
        {
            get { return _measureMode; }
            set { _measureMode = value; }
        }

        private string _mapDatum;
        /// <summary>
        /// Indicates the geodetic survey data used by the GPS receiver. If the survey data is restricted to Japan, the value of this tag is 'TOKYO' or 'WGS-84'.
        /// </summary>
        public string MapDatum
        {
            get { return _mapDatum; }
            set { _mapDatum = value; }
        }
    }

    public class GPSPosition
    {
        public GPSPosition(int degrees, int minutes, decimal seconds, GPSReference reference)
        {
            _degrees = degrees;
            _minutes = minutes;
            _seconds = seconds;
            _reference = reference;
        }

        private GPSReference _reference;
        public GPSReference Reference
        {
            get { return _reference; }
            set { _reference = value; }
        }

        private int _degrees;
        public int Degrees
        {
            get { return _degrees; }
            set { _degrees = value; }
        }

        private int _minutes;
        public int Minutes
        {
            get { return _minutes; }
            set { _minutes = value; }
        }

        private decimal _seconds;
        public decimal Seconds
        {
            get { return _seconds; }
            set { _seconds = value; }
        }

        public decimal ToDecimal()
        {
            //Formula found from http://pukupi.com/articles/exif/
            //Thanks to Kyle Barrow for this formula.

            int r = 1;
            if (Reference == GPSReference.S || Reference == GPSReference.W)
                r = -1;

            return (_degrees + (((_minutes * 60) + (_seconds)) / 3600)) * r;
        }

        public override string ToString()
        {
            return _degrees + "°" + _minutes + "'" + _seconds + "\"" + _reference.ToString();
        }
    }

    public enum GPSReference
    {
        N,
        E,
        S,
        W
    }

    public enum GPSAltitudeRef
    { 
        SeaLevelOrAbove=0,
        BelowSeaLevel=1,
        Other
    }

    public enum GPSStatus
    {
        NotSpecified,
        InProgress,
        Interoperability,
        Other
    }

    public enum GPSMeasureMode
    {
        NotSpecified,
        TwoDimensional,
        ThreeDimensional,
        Other
    }
}
